package org.jeecg.modules.flow.utils;

import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.HistoricActivityInstanceQueryImpl;
import org.activiti.engine.impl.HistoricTaskInstanceQueryImpl;
import org.activiti.engine.impl.Page;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.*;
import org.activiti.engine.impl.util.CollectionUtil;
import org.activiti.engine.runtime.Execution;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

public class Jump2FrontTargetFlowNodeCommand implements Command<Void> {

    //流程实例Id
    private final String processInstanceId;
    //要跳转到的目标节点们后面所有的节点
    private List<String> toDealTaskDefIdList;
    //跳转的原因,动作,比如本步骤撤销,审核拒绝,撤回到上面某一步
    private String action;
    //要跳转到的目标节点列表
    private List<String> targetFlowNodeIdList;
    private Map assigneeMap;
    //目标节点的类型,如果是会签这种多个执行人的节点为"multi",如果是正常的单个执行人的节点为"single"
    private String targetFlowNodeType;
    //bpmnModel
    private BpmnModel bpmnModel;
    private RuntimeService runtimeService;

    /**
     * 保存撤回节点的变量map
     */
    private Map<String, List<VariableInstanceEntity>> varMap = new ConcurrentHashMap<>();

    public Jump2FrontTargetFlowNodeCommand(String processInstanceId, List<String> toDealTaskDefIdList,
                                           List<String> targetFlowNodeIdList, Map assigneeMap,
                                           String targetFlowNodeType,
                                           BpmnModel bpmnModel, String action,
                                           RuntimeService runtimeService) {
        this.processInstanceId = processInstanceId;
        this.bpmnModel = bpmnModel;
        this.action = action;
        this.toDealTaskDefIdList = toDealTaskDefIdList;
        this.targetFlowNodeIdList = targetFlowNodeIdList;
        this.assigneeMap = assigneeMap;
        this.targetFlowNodeType = targetFlowNodeType;
        this.runtimeService = runtimeService;

    }

    @Override
    public Void execute(CommandContext commandContext) {
        ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
        // 处理进行中的任务
        handleDoingTask(commandContext);
        // 处理已经完成的任务
        handleCompletedTask(commandContext);
        targetFlowNodeIdList.forEach(targetId -> {
            UserTask userTask = (UserTask) bpmnModel.getFlowElement(targetId);
            // 创建子执行流，开启任务
            ExecutionEntity processExecution = executionEntityManager.findById(processInstanceId);
            ExecutionEntity childExecution = executionEntityManager.createChildExecution(processExecution);
            childExecution.setCurrentFlowElement(userTask);

            // 设置执行变量
            VariableInstanceEntityManager variableManager = commandContext.getVariableInstanceEntityManager();
            List<VariableInstanceEntity> variableInstanceEntities = varMap.get(userTask.getId());
            if (CollectionUtil.isNotEmpty(variableInstanceEntities)) {
                variableInstanceEntities.forEach(var -> {
                    var.setExecution(childExecution);
                    variableManager.insert(var);
                });
            }
            //设置执行人
            targetFlowNodeIdList.forEach(stepId -> {
                if (assigneeMap.get(stepId) != null) {
                    String assigneeStr = assigneeMap.get(stepId).toString();
                    //设置执行人,如果是多人的,参数应该传list
/*  // TODO                  if(CommonEnum.NODE_ASSIGNEE_MULTI.getValue().equals(targetFlowNodeType)){
                        List<String> assigneeList = CommonUtil.strToList(assigneeStr);
                        childExecution.setVariable(stepId, assigneeList);
                    }else if(CommonEnum.NODE_ASSIGNEE_SINGLE.getValue().equals(targetFlowNodeType)){
                        childExecution.setVariable(stepId, assigneeStr);
                    }*/
                }
            });
            commandContext.getExecutionEntityManager().insert(childExecution);
            // 交给activiti流转
            commandContext.getAgenda().planContinueProcessOperation(childExecution);
        });
        return null;
    }

    private void handleCompletedTask(CommandContext commandContext) {
        HistoricTaskInstanceEntityManager historicTaskManager = commandContext.getHistoricTaskInstanceEntityManager();
        VariableInstanceEntityManager variableInstanceEntityManager = commandContext.getVariableInstanceEntityManager();
        ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
        List<String> deleteExecutionIdList = new ArrayList<>();
        for (String str : toDealTaskDefIdList) {
            HistoricActivityInstanceQueryImpl query =
                    new HistoricActivityInstanceQueryImpl().activityId(str).processInstanceId(processInstanceId);
            List<HistoricActivityInstance> activityInstances =
                    commandContext.getHistoricActivityInstanceEntityManager().findHistoricActivityInstancesByQueryCriteria(query, new Page(0, Integer.MAX_VALUE));
            for (HistoricActivityInstance activity : activityInstances) {
                HistoricActivityInstanceEntity activityEntity = (HistoricActivityInstanceEntity) activity;
                //删除act_ru_execution表
                ExecutionEntity executionEntity = executionEntityManager.findById(activity.getExecutionId());
                //删除父Execution时,好像会自动删除他的子Execution,这里如果不加判断,到了删除子Execution时,就会报乐观锁异常,所以,
                //每删除一个Execution,找出他的子Execution,这些子Execution不在进行删除
                if (executionEntity != null && (deleteExecutionIdList.size() == 0 || !deleteExecutionIdList.contains(executionEntity.getId()))) {
                    //因为外键约束,首先要删除variable表中的execution相关数据
                    List<VariableInstanceEntity> variableInstances =
                            variableInstanceEntityManager.findVariableInstancesByExecutionId(executionEntity.getId());
                    varMap.put(executionEntity.getActivityId(), variableInstances);
                    variableInstances.forEach(variableInstanceEntityManager::delete);
                    executionEntityManager.delete(executionEntity);
                    List<ExecutionEntity> childExecutions =
                            executionEntityManager.findChildExecutionsByParentExecutionId(executionEntity.getId());
                    deleteExecutionIdList.addAll(childExecutions.stream().map(ExecutionEntity::getId).collect(Collectors.toList()));
                }
                //删除act_hi_actinst表
                activityEntity.setDeleted(true);
                activityEntity.setDeleteReason(action);
                commandContext.getHistoricActivityInstanceEntityManager().update(activityEntity);
                historicTaskManager.delete(activity.getTaskId());
            }
        }
    }

    private void handleDoingTask(CommandContext commandContext) {
        ExecutionEntityManager executionEntityManager = commandContext.getExecutionEntityManager();
        HistoricTaskInstanceEntityManager historicTaskManager = commandContext.getHistoricTaskInstanceEntityManager();
        VariableInstanceEntityManager variableManager = commandContext.getVariableInstanceEntityManager();
        for (String str : toDealTaskDefIdList) {
            List<Execution> executionEntities = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).activityId(str).list();
            for (Execution parentExecution : executionEntities) {
                //关闭未完成的任务执行流
                List<ExecutionEntity> childExecutions =
                        executionEntityManager.findChildExecutionsByParentExecutionId(parentExecution.getId());
                for (ExecutionEntity childExecution : childExecutions) {
                    //因为外键约束,首先要删除variable表中的execution相关数据
                    List<VariableInstanceEntity> variableInstances =
                            variableManager.findVariableInstancesByExecutionId(childExecution.getId());
                    varMap.put(parentExecution.getActivityId(), variableInstances);
                    variableInstances.forEach(variableManager::delete);
                    executionEntityManager.deleteExecutionAndRelatedData(childExecution, action, false);
                    // 删除历史实例
                    HistoricTaskInstanceQueryImpl query = new HistoricTaskInstanceQueryImpl().executionId(childExecution.getId()).processInstanceId(processInstanceId);
                    List<HistoricTaskInstance> historicTaskInstancesByQueryCriteria =
                            historicTaskManager.findHistoricTaskInstancesByQueryCriteria(query);
                    if (CollectionUtil.isNotEmpty(historicTaskInstancesByQueryCriteria)) {
                        for (HistoricTaskInstance historicTaskInstancesByQueryCriterion :
                                historicTaskInstancesByQueryCriteria) {
                            commandContext.getHistoricTaskInstanceEntityManager().delete(historicTaskInstancesByQueryCriterion.getId());
                        }
                    }
                }
                //父执行流关闭
                List<VariableInstanceEntity> variableInstances =
                        variableManager.findVariableInstancesByExecutionId(parentExecution.getId());
                varMap.put(parentExecution.getActivityId(), variableInstances);
                variableInstances.forEach(variableManager::delete);
                ExecutionEntity parentExecution1 = (ExecutionEntity) parentExecution;
                executionEntityManager.deleteExecutionAndRelatedData(parentExecution1, action, false);
            }
        }
    }
}

